using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Collections.Specialized;

namespace ru.yourpictures.Core.Imaging.Filters.PhotoFilters
{
    /// <summary>
    /// Box filter class. Creates an isometric box and renders the image on that specific view . Gives a 3d view.
    /// Reference: http://www.codeproject.com/KB/cs/yael_image_filters.aspx
    /// </summary>
    [FilterImplementation(GdiPlusImplemented = true, LowLevelImplemented = false)]
    public class Box : FilterBase
    {
        #region Private Fields
        private double _alpha = Math.PI / 6; //30deg
        private int _boxDepth = 10;
        private System.Drawing.Color _boxStartColor = System.Drawing.Color.DarkBlue;
        private System.Drawing.Color _boxEndColor = System.Drawing.Color.LightBlue;
        private Image _topPanelImage = null;
        private Image _sidePanelImage = null;
        #endregion Private Fields

        #region Filter Properties
        /// <summary>
        /// The angle in degrees (x/360) box will be inlined to
        /// </summary>
        public double Alpha
        {
            get { return _alpha; }
            set { _alpha = value; }
        }

        /// <summary>
        /// Defines the "3d" depth of the box, i.e. "thickness" of the box in pixels
        /// </summary>
        public int BoxDepth
        {
            get{return _boxDepth;}
            set{_boxDepth = value;}
        }
        /// <summary>
        /// Sets the starting color of the box gradient brush
        /// </summary>
        public System.Drawing.Color BoxStartColor
        {
            get{return _boxStartColor;}
            set{_boxStartColor = value;}
        }
        /// <summary>
        /// Sets the ending color of the box gradient brush
        /// </summary>
        public System.Drawing.Color BoxEndColor
        {
            get{return _boxEndColor;}
            set{_boxEndColor = value;}
        }
        /// <summary>
        /// A side panel image, reset to null to turn off and use the regular gradient
        /// </summary>
        public Image SidePanelImage
        {
            get { return _sidePanelImage; }
            set { _sidePanelImage = value; }
        }
        /// <summary>
        /// A top panel image, reset to null to turn off and use the regular gradient
        /// </summary>
        public Image TopPanelImage
        {
            get { return _topPanelImage; }
            set { _topPanelImage = value; }
        }

        #endregion Filter Properties

        #region Ctor
        public Box(double alpha, int boxDepth, System.Drawing.Color boxStartColor, System.Drawing.Color boxEndColor)
        {
            _alpha = alpha;
            _boxDepth = boxDepth;
            _boxStartColor = boxStartColor;
            _boxEndColor = boxEndColor;
        }
        public Box(double alpha, int boxDepth, Image topPanelImage, Image sidePanelImage)
        {
            _alpha = alpha;
            _boxDepth = boxDepth;
            _topPanelImage = topPanelImage;
            _sidePanelImage = sidePanelImage;
        }
        public Box(double alpha, int boxDepth)
        {
            _alpha = alpha;
            _boxDepth = boxDepth;
        }
        public Box() { }
        #endregion

        #region Public Filter Methods
        /// <summary>
        /// Executes this filter on the input image and returns the result
        /// </summary>
        /// <param name="inputImage">input image</param>
        /// <returns>transformes image into a boxed layout</returns>
        /// <example>
        /// <code>
        /// Image transformed;
        /// BoxFilter box = new BoxFilter();
        /// box.BoxDepth = 20;
        /// box.BoxStartColor = Color.Tan;
        /// box.BoxEndColor = Color.Wheat;
        /// transformed = box.ExecuteFilter(myImg);
        /// </code>
        /// </example>
        public override void Apply(Bitmap b)
        {
            _b = b;

            //Setting up the box 3d depth values.
            int sideWidth = _boxDepth;
            int sideHeight = b.Height;
            int topWidth = b.Width;
            int topHeight = sideWidth;

            // Calculate total picture width and height and create bitmap for it
            int totalWidth = (int)(sideWidth * Math.Cos(_alpha) + b.Width * Math.Cos(_alpha));
            int totalHeight = (int)(b.Height + b.Width * Math.Sin(_alpha) + sideWidth * Math.Sin(_alpha));

            //Set up the new canvas
            Bitmap result = new Bitmap(totalWidth,totalHeight);
            Graphics g = Graphics.FromImage(result);
            // Set interpolation mode
            g.InterpolationMode = _interpolationMode;
            //Set background
            g.FillRectangle(new SolidBrush(BackGroundColor), 0, 0, result.Width, result.Height);


            //FrontSide
            //Point rightBottom = new Point((int)(raw.Width * Math.Cos(alpha)) , raw.Height - (int)(raw.Width * Math.Sin(alpha)) + yAlign);
            Point leftTop = new Point((int)(sideWidth * Math.Cos(_alpha)), (int)((sideWidth + b.Width) * Math.Sin(_alpha)));
            Point leftBottom = new Point((int)(sideWidth * Math.Cos(_alpha)), b.Height + (int)((sideWidth + b.Width) * Math.Sin(_alpha)));
            Point rightTop = new Point((int)((b.Width + sideWidth) * Math.Cos(_alpha)), (int)(sideWidth * Math.Sin(_alpha)));
            g.DrawImage(b, new Point[] { leftTop, rightTop, leftBottom });


            //TopSide
            Point topUpperRight = new Point(rightTop.X - (int)(topHeight * Math.Cos(_alpha)), rightTop.Y - (int)(topHeight * Math.Sin(_alpha)));
            Point topLowerRight = new Point(rightTop.X, rightTop.Y);
            Point topLowerLeft = new Point(leftTop.X, leftTop.Y);
            Point topUpperLeft = new Point(leftTop.X - (int)(sideWidth * Math.Cos(_alpha)), leftTop.Y - (int)(sideWidth * Math.Sin(_alpha)));
            
            Point[] top = new Point[4];
            top[0] = topUpperLeft;
            top[1] = topUpperRight;
            top[2] = topLowerRight;
            top[3] = topLowerLeft;
            
            if (_topPanelImage != null)
                g.DrawImage(_topPanelImage, new Point[] { topUpperLeft, topUpperRight, topLowerLeft });
            else
            {
                LinearGradientBrush topBrush = new LinearGradientBrush(topLowerRight, topUpperLeft, _boxStartColor, _boxEndColor);
                g.FillPolygon(topBrush, top);
            }


            //LeftSide
            Point sideUpperRight = new Point(leftTop.X, leftTop.Y);
            Point sideLowerRight = new Point(leftBottom.X, leftBottom.Y);
            Point sideLowerLeft = new Point(leftBottom.X - (int)(sideWidth * Math.Cos(_alpha)), leftBottom.Y - (int)(sideWidth * Math.Sin(_alpha)));
            Point sideUpperLeft = new Point(leftTop.X - (int)(sideWidth * Math.Cos(_alpha)), leftTop.Y - (int)(sideWidth * Math.Sin(_alpha)));
            
            Point[] side = new Point[4];
            side[0] = sideUpperLeft;
            side[1] = sideUpperRight;
            side[2] = sideLowerRight;
            side[3] = sideLowerLeft;

            if (_sidePanelImage != null)
                g.DrawImage(_sidePanelImage, new Point[] { sideUpperLeft, sideUpperRight, sideLowerLeft });
            else
            {
                LinearGradientBrush sideBrush = new LinearGradientBrush(sideUpperLeft, sideLowerRight, _boxStartColor, _boxEndColor);
                g.FillPolygon(sideBrush, side);
            }

            b.Dispose();
            b = result;
        }

        public override Bitmap Convert(Bitmap b)
        {
            Bitmap ret = new Bitmap(b);
            Apply(ret);
            return ret;
        }
        #endregion Public Filter Methods

        protected override void FilterImplementation()
        {
            throw new NotImplementedException("Low level mode is not implemented");
        }
    }
}
